package ${basePackage}.core.aware;

import ${basePackage}.core.model.LoginUserInfo;
import ${basePackage}.core.model.PageWrap;
import ${basePackage}.dao.system.model.SystemDataPermission;
import ${basePackage}.service.system.SystemDataPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 默认数据权限控制
 *
 * @author Eva.Caesar Liu
 * @since 2023/08/27 15:22
 */
@Slf4j
@Component
public abstract class DefaultDataPermissionAware<T> implements DataPermissionAware<T> {

    @Autowired
    private SystemDataPermissionService systemDataPermissionService;

    /**
     * 执行数据权限查询
     *
     * @return T
     */
    public T execute(PageWrap pageWrap) {
        try {
            // 获取登录用户
            LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
            // 获取数据权限配置
            List<SystemDataPermission> dataPermissions = systemDataPermissionService.findDataPermission(this.module().getBusinessCode(), loginUserInfo.getRoles());
            // - 无数据权限配置返回默认数据
            if (CollectionUtils.isEmpty(dataPermissions)) {
                Method[] methods = this.getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if ("defaultData".equals(method.getName())) {
                        return (T) method.invoke(this, this.getRejectParameters(method, loginUserInfo, null, pageWrap));
                    }
                }
                return null;
            }
            // 按角色的数据权限优先级返回数据
            // - 将权限方法优先级排列
            Method[] methods = this.getClass().getDeclaredMethods();
            Map<Integer, Method> sortedMethods = new TreeMap<>();
            for (Method method : methods) {
                DataPermissionMapping mapping = method.getAnnotation(DataPermissionMapping.class);
                if (mapping == null) {
                    continue;
                }
                if (sortedMethods.get(mapping.priority()) != null) {
                    throw new AnnotationConfigurationException("EVA: data permission contains the same priority.");
                }
                sortedMethods.put(mapping.priority(), method);
            }
            // - 按序执行权限方法
            for (Map.Entry<Integer, Method> entry : sortedMethods.entrySet()) {
                Method method = entry.getValue();
                DataPermissionMapping mapping = method.getAnnotation(DataPermissionMapping.class);
                for (SystemDataPermission dataPermission : dataPermissions) {
                    if (!dataPermission.getType().equals(mapping.value().getCode())) {
                        continue;
                    }
                    return (T) method.invoke(this, this.getRejectParameters(method, loginUserInfo, dataPermission, pageWrap));
                }
            }
        } catch (Exception e) {
            throw new AnnotationConfigurationException("EVA: data permission dead.", e);
        }
        throw new IllegalStateException("EVA: no type found of data permission.");
    }

    /**
     * 执行数据权限查询
     *
     * @return T
     */
    public T execute() {
        return this.execute(null);
    }

    /**
     * 获取动态注入参数数组
     *
     * @param method 方法
     * @param loginUserInfo 用户登录对象
     * @param dataPermission 数据权限对象
     * @param pageWrap 分页参数对象
     * @return Object[]
     */
    private Object[] getRejectParameters (Method method, LoginUserInfo loginUserInfo, SystemDataPermission dataPermission, PageWrap pageWrap) {
        Type[] parameterTypes = method.getGenericParameterTypes();
        List<Object> parameters = new ArrayList<>();
        for (Type type : parameterTypes) {
            // 注入当前登录用户ID
            if (Integer.class.getName().equals(type.getTypeName())) {
                parameters.add(loginUserInfo.getId());
            }
            // 注入自定义数据
            if (String.class.getName().equals(type.getTypeName())) {
                parameters.add(dataPermission.getCustomData());
            }
            // 注入分页参数
            if (type.getTypeName().startsWith(PageWrap.class.getName())) {
                parameters.add(pageWrap);
            }
        }
        return parameters.toArray();
    }

}
